#include "gtest/gtest.h"

//#include "../../Common/include/Constant.h"
//#include "../include/Vector3D.h"

#include "Vector3D.h"

// using SG::DataStructure::Common::TOLERANCE;
// using SG::Algebra::Matrixd;
// using SG::Algebra::Vector3D;

using namespace SG::Algebra;

TEST (Vector3DTest, NormalizeTest)
{
    // Input
    Vector3D a{ 3.0, 4.0, 12.0 };

    // Test data
    Real_t normTest;
    a.Normalize (normTest);

    // Target data
    Real_t normTarget{ 13.0 };
    Vector3D                        aTarget{ 3.0 / 13.0, 4.0 / 13.0, 12.0 / 13.0 };

    // Check
    ASSERT_TRUE (a == aTarget);
    ASSERT_NEAR (normTest, normTarget, TOLERANCE);
}

TEST (Vector3DTest, Normalize1Test)
{
    // Input
    Vector3D a{ 3.0, 4.0, 12.0 };

    // Test data
    a.Normalize ();

    // Target data
    Vector3D                        aTarget{ 3.0 / 13.0, 4.0 / 13.0, 12.0 / 13.0 };

    // Check
    ASSERT_TRUE (a == aTarget);
}

TEST (Vector3DTest, RotateTest)
{
    // Input data
    Matrixd  T (3, 3, { 0.63125150, -0.35830835, 0.68784931, 0.53169580, 0.84560449, -0.047461879, -0.56464247, 0.39568697, 0.72430014 });
    Vector3D vec{ 1.0, 2.0, 3.0 };

    // Test data
    Vector3D vecTest = vec.Rotate (T);

    // Target data
    Vector3D vecTarget{ 1.9781827, 2.0805191, 2.3996319 };

    // Check
    ASSERT_TRUE (vecTarget == vecTest);
}

TEST (Vector3DTest, multiFactorTest)
{
    // Input
    Vector3D a{ 3.0, 4.0, 12.0 };

    // Test data
    auto     aTest = a * 0.3;
    Vector3D aTarget{ 0.9, 1.2, 3.6 };

    // Check
    ASSERT_TRUE (aTest == aTarget);
}

TEST (Vector3DTest, multiEqualFactorTest)
{
    // Input
    Vector3D aTest{ 3.0, 4.0, 12.0 };

    // Test data
    aTest *= 0.3;
    Vector3D aTarget{ 0.9, 1.2, 3.6 };

    // Check
    ASSERT_TRUE (aTest == aTarget);
}

TEST (Vector3DTest, addOperatorTest)
{
    // Input
    Vector3D aTest{ 3.0, 4.0, 12.0 };
    Vector3D bTest{ 1.0, 2.0, 3.0 };
    // Test data
    Vector3D result = aTest + bTest;
    Vector3D resultTarget{ 4.0, 6.0, 15.0 };

    // Check
    ASSERT_TRUE (result == resultTarget);
}

TEST (Vector3DTest, addEqualOperatorTest)
{
    // Input
    Vector3D aTest{ 3.0, 4.0, 12.0 };
    Vector3D bTest{ 1.0, 2.0, 3.0 };
    // Test data
    aTest += bTest;
    Vector3D aTestTarget{ 4.0, 6.0, 15.0 };

    // Check
    ASSERT_TRUE (aTest == aTestTarget);
}

TEST (Vector3DTest, subOperatorTest)
{
    // Input
    Vector3D aTest{ 3.0, 4.0, 12.0 };
    Vector3D bTest{ 1.0, 2.0, 3.0 };
    // Test data
    Vector3D result = aTest - bTest;
    Vector3D resultTarget{ 2.0, 2.0, 9.0 };

    // Check
    ASSERT_TRUE (result == resultTarget);
}

TEST (Vector3DTest, subEqualOperatorTest)
{
    // Input
    Vector3D aTest{ 3.0, 4.0, 12.0 };
    Vector3D bTest{ 1.0, 2.0, 3.0 };
    // Test data
    aTest -= bTest;
    Vector3D aTestTarget{ 2.0, 2.0, 9.0 };

    // Check
    ASSERT_TRUE (aTest == aTestTarget);
}

TEST (Vector3DTest, IsZeroTest)
{
    // Input
    Vector3D a{ 3.0, 4.0, 12.0 };
    Vector3D zero{ 0.0, 0.0, 0.0 };

    // Check
    ASSERT_TRUE (false == a.IsZero ());
    ASSERT_TRUE (true == zero.IsZero ());
}

TEST (Vector3DTest, CrossTest)
{
    // Input
    Vector3D a{ 1.0, 0.0, 0.0 };
    Vector3D b{ 0.0, 1.0, 0.0 };

    // Test data
    auto cTest = Cross (a, b);

    // Target data
    Vector3D cTarget{ 0.0, 0.0, 1.0 };

    // Check
    ASSERT_TRUE (cTest == cTarget);
}

TEST (Vector3DTest, dotTest)
{
    // Input
    Vector3D a{ 2.0, 3.0, 4.0 };
    Vector3D b{ 1.0, 2.0, 3.0 };

    // Test data
    auto cTest = dot (a, b);

    // Target data
    Real_t cTarget = 20.0;

    // Check
    ASSERT_NEAR (cTest, cTarget, TOLERANCE);
}